package com.thouiot.modbus.util;

import com.thouiot.common.exception.TiotRuntimeException;
import com.thouiot.modbus.config.ModbusTypeEnum;
import com.thouiot.modbus.entity.vo.ModbusLocatorVo;
import com.thouiot.modbus.enums.ReadValueTypeEnum;
import com.thouiot.modbus.enums.RegisterTypeEnum;
import com.thouiot.modbus.enums.WriteValueTypeEnum;
import com.thouiot.modbus.exception.ModbusErrorCodeEnum;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * @description Modbus参数工具类
 * @author wangkai
 * @date 2025/04/16 15:18
 */
public class ModbusParamsUtil {

    /**
     * 校验基本参数
     * @param locatorVo
     */
    public static void checkBaseParams(ModbusLocatorVo locatorVo) {
        if (locatorVo == null) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.PARAM_EMPTY_ERROR);
        }
        if (StringUtils.isBlank(locatorVo.getModbusType())) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.MASTER_TYPE_EMPTY_ERROR);
        }
        ModbusTypeEnum masterTypeEnum = ModbusTypeEnum.getModbusTypeEnum(locatorVo.getModbusType());
        if (masterTypeEnum == null) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.MASTER_TYPE_NOT_SUPPORT);
        }
        if (StringUtils.isBlank(locatorVo.getName())) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.MASTER_NAME_EMPTY_ERROR);
        }
        if (locatorVo.getSlaveId() == null) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.SLAVE_ID_EMPTY_ERROR);
        }
        if (locatorVo.getOffset() == null) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.OFFSET_EMPTY_ERROR);
        }
    }

    /**
     * 校验寄存器类型和读取值类型是否匹配
     *
     * @param registerType
     * @param readValueType
     */
    public static void checkRegisterReadType(String registerType, String readValueType) {
        RegisterTypeEnum registerTypeEnum = RegisterTypeEnum.getRegisterTypeEnum(registerType);
        ReadValueTypeEnum readValueTypeEnum = ReadValueTypeEnum.getReadValueTypeEnum(readValueType);
        if (registerTypeEnum == null) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.REGISTER_TYPE_ERROR);
        }
        if (readValueTypeEnum == null) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.READ_VALUE_TYPE_ERROR);
        }
        // 只有保持寄存器，输入寄存器才可以读取数字或数字数组
        if (ReadValueTypeEnum.SHORTS.equals(readValueTypeEnum) || ReadValueTypeEnum.NUMBER.equals(readValueTypeEnum) || ReadValueTypeEnum.SHORT.equals(readValueTypeEnum)) {
            if (!RegisterTypeEnum.HOLDING_REGISTER.equals(registerTypeEnum) && !RegisterTypeEnum.INPUT_REGISTER.equals(registerTypeEnum)) {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.READ_VALUE_TYPE_NOT_MATCH);
            }
        }
        // 线圈和离散输入，可以读取单个状态值或状态值数组
        if (ReadValueTypeEnum.BOOLEAN.equals(readValueTypeEnum) || ReadValueTypeEnum.BOOLEANS.equals(readValueTypeEnum)) {
            if (!RegisterTypeEnum.COIL_INPUT.equals(registerTypeEnum) && !RegisterTypeEnum.DISCRETE_INPUT.equals(registerTypeEnum)) {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.READ_VALUE_TYPE_NOT_MATCH);
            }
        }
    }

    /**
     * 校验写入参数值 和 指定的写入参数类型 是否匹配
     * 目前支持 5种类型，boolean, short, number, boolean[], short[]，参考 WriteValueTypeEnum
     * @param valueTypeEnum
     * @param value
     */
    public static void checkValueTypeMatchValue(WriteValueTypeEnum valueTypeEnum, Object value) {
        if (WriteValueTypeEnum.BOOLEAN.equals(valueTypeEnum)) {
            if (!(value instanceof Boolean)) {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
            }
        } else if (WriteValueTypeEnum.BOOLEANS.equals(valueTypeEnum)) {
            if (value instanceof List) {
                Object temp = ((List) value).get(0);
                if (!(temp instanceof Boolean)) {
                    throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
                }
            } else {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
            }
        } else if (WriteValueTypeEnum.SHORT.equals(valueTypeEnum)) {
            if (!(value instanceof Integer)) {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
            }
        } else if (WriteValueTypeEnum.SHORTS.equals(valueTypeEnum)) {
            if (value instanceof List) {
                Object temp = ((List) value).get(0);
                if (!(temp instanceof Integer)) {
                    throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
                }
            } else {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
            }
        }else if (WriteValueTypeEnum.NUMBER.equals(valueTypeEnum)) {
            if (!(value instanceof Number)) {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
            }
        } else if (WriteValueTypeEnum.NUMBERS.equals(valueTypeEnum)) {
            if (value instanceof List) {
                Object temp = ((List) value).get(0);
                if (!(temp instanceof Number)) {
                    throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
                }
            } else {
                throw new TiotRuntimeException(ModbusErrorCodeEnum.WRITE_VALUE_TYPE_NOT_MATCH);
            }
        }
    }

    /**
     * 校验存储区类型 和 指定的写入参数类型 是否匹配
     * 只有线圈和离散输入存储区，可以写入单个状态值或状态值数组；只有保持寄存器和输入寄存器，可以写入数字或数字数组
     * @param registerType
     * @param valueType
     */
    public static void checkRegisterTypeMatchValueType(RegisterTypeEnum registerType, WriteValueTypeEnum valueType, boolean isSlave) {
        if (WriteValueTypeEnum.BOOLEAN.equals(valueType) || WriteValueTypeEnum.BOOLEANS.equals(valueType)) {
            if (isSlave) {
                if (!RegisterTypeEnum.COIL_INPUT.equals(registerType) && !RegisterTypeEnum.DISCRETE_INPUT.equals(registerType)) {
                    throw new TiotRuntimeException(ModbusErrorCodeEnum.REGISTER_TYPE_MATCH_VALUE_ERROR);
                }
            } else {
                if (!RegisterTypeEnum.COIL_INPUT.equals(registerType)) {
                    throw new TiotRuntimeException(ModbusErrorCodeEnum.REGISTER_TYPE_MATCH_VALUE_ERROR);
                }
            }
        }
        if (WriteValueTypeEnum.SHORT.equals(valueType) || WriteValueTypeEnum.SHORTS.equals(valueType)
                || WriteValueTypeEnum.NUMBER.equals(valueType) || WriteValueTypeEnum.NUMBERS.equals(valueType)) {
            if (isSlave) {
                if (!RegisterTypeEnum.HOLDING_REGISTER.equals(registerType) && !RegisterTypeEnum.INPUT_REGISTER.equals(registerType)) {
                    throw new TiotRuntimeException(ModbusErrorCodeEnum.REGISTER_TYPE_MATCH_VALUE_ERROR);
                }
            } else {
                if (!RegisterTypeEnum.HOLDING_REGISTER.equals(registerType)) {
                    throw new TiotRuntimeException(ModbusErrorCodeEnum.REGISTER_TYPE_MATCH_VALUE_ERROR);
                }
            }
        }
    }

    public static void checkRegisterTypeMatchValueType(RegisterTypeEnum registerType, WriteValueTypeEnum valueType) {
        checkRegisterTypeMatchValueType(registerType, valueType, false);
    }
}
